package vg.modules.graph_layout_viewer;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import vg.services.graph_layout_manager.interfaces.IGraphLayout;
import vg.services.main_manager.MainManager;
import vg.services.plugin_manager.realization.PluginParameter;

public abstract class GraphLayoutPanel extends JFrame {
	private static final long serialVersionUID = 1L;
	
	// Main data
	private boolean init = false;
	//private PluginParameter pluginParameter;
	private List<IGraphLayout> layouts;
	
	// Mutex
	private final Object generalMutex = new Object();

	// Swing components
	private JPanel settingsPanel = new JPanel();
	protected JComboBox layoutList = new JComboBox();
	private JButton okButton = new JButton("Ok");
	private JButton executeButton = new JButton("Execute");
	private JButton cancelButton = new JButton("Cancel");
	
	/**
	 * Constructor.
	 */
	public GraphLayoutPanel(PluginParameter param) {
		//this.pluginParameter = param;
	}
	
	public void open() {
		synchronized (generalMutex) {
			if(!init) {
				init();
			}
			updateLayouts(MainManager.graphLayoutManager.getInstalledLayouts(), MainManager.graphLayoutManager.getCurrentLayout());
			setVisible(true);
		}
	}
	
	public void repaint() {
		super.repaint();		
		setMinimumSize(this.getPreferredSize());
		pack();
	}
	
//=============================================================================
//-----------------PRIVATE METHODS---------------------------------------------
	private void updateLayouts(List<IGraphLayout> layouts, IGraphLayout selectedLayout) {
		this.layouts = layouts;
		
		// update list
		layoutList.removeAllItems();
		int index = -1, i = 0;
		for (IGraphLayout buf : layouts) {
			if (buf.equals(selectedLayout)) {
				index = i; 
			}
			layoutList.addItem(buf.getName());
			i++;
		}
		
		if (index >= 0)
			layoutList.setSelectedIndex(index);
	}

	private void updateSettingPanel(int index) {
		// find layout wrapper in list
		int i = 0;
		IGraphLayout tmp_lw = null;
		for (IGraphLayout buf : layouts) {
			if (index == i) {
				tmp_lw = buf;
				break;
			}
			i++;
		}
		final IGraphLayout lw = tmp_lw;
		MainManager.graphLayoutManager.setCurrentLayout(lw);
		
		// clear all list
		settingsPanel.removeAll();
		// return if layout wrapper = 0
		if (lw == null) return;
		// get settings from current layout wrapper
		final Map<String, Object> settings = lw.getSettings();
		// return if settings = 0		
		if (settings == null) return;
		
		// build settings panel
		i = 0;
		for (final String s:settings.keySet()) {
			GridBagConstraints gbc = new GridBagConstraints(0, i, 1, 1, 1,0,  GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5),  0,0);
			settingsPanel.add(new JLabel(s), gbc);

			gbc = new GridBagConstraints(1, i, 1, 1, 1,0,  GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5),  0,0);
			if (settings.get(s) instanceof Boolean) {
				Boolean boolValue = (Boolean) settings.get(s);
				final JCheckBox checkbox = new JCheckBox();
				checkbox.setSelected(boolValue);
				checkbox.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						settings.put(s, checkbox.isSelected());
						lw.setSettings(settings);
					}
				});
				settingsPanel.add(checkbox, gbc);
			} else if (settings.get(s) instanceof Double) {
				Double doubleValue = (Double) settings.get(s);
				final JTextField te = new JTextField();
				te.setText(doubleValue.toString());
				te.getDocument().addDocumentListener(new DocumentListener() {
					public void removeUpdate(DocumentEvent e) {
						String str = te.getText();
						if (str != null && str.length() > 0)
							try {
								settings.put(s, Double.parseDouble(str));
							} catch (NumberFormatException e1) {
								te.setText(settings.get(s).toString());
								te.repaint();
							} finally {
								lw.setSettings(settings);								
							}
					}
					public void insertUpdate(DocumentEvent e) {
						String str = te.getText();
						if (str != null && str.length() > 0)
							try {
								settings.put(s, Double.parseDouble(str));
							} catch (NumberFormatException e1) {
								te.setText(settings.get(s).toString());
								te.repaint();
							} finally {
								lw.setSettings(settings);								
							}
					}
					public void changedUpdate(DocumentEvent e) {

					}
				});
				settingsPanel.add(te, gbc);
			} else if (settings.get(s) instanceof Integer) {
				Integer intValue = (Integer) settings.get(s);
				final JFormattedTextField te = new JFormattedTextField();
				te.setValue(intValue);
				te.getDocument().addDocumentListener(new DocumentListener() {
					public void removeUpdate(DocumentEvent e) {
						String str = te.getText();
						if (str != null && str.length() > 0)
							try {
								settings.put(s, Integer.parseInt(str));
							} catch (NumberFormatException e1) {
								te.setText(settings.get(s).toString());
								te.repaint();
							} finally {
								lw.setSettings(settings);								
							}
					}
					public void insertUpdate(DocumentEvent e) {
						String str = te.getText();
						if (str != null && str.length() > 0)
							try {
								settings.put(s, Integer.parseInt(str));
							} catch (NumberFormatException e1) {
								te.setText(settings.get(s).toString());
								te.repaint();
							} finally {
								lw.setSettings(settings);								
							}
					}
					public void changedUpdate(DocumentEvent e) {

					}
				});
				settingsPanel.add(te, gbc);
			}

			i++;
		}
		settingsPanel.updateUI();
		this.setMinimumSize(this.getPreferredSize());
		this.pack();
	}
	
	/**
	 * This method updates ui theme of filter plugin.
	 */
	public void updateUITheme() {
		synchronized (generalMutex) {
			if(init) {
				if (SwingUtilities.isEventDispatchThread()) {
					SwingUtilities.updateComponentTreeUI(GraphLayoutPanel.this.getContentPane());
				} else {
					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							synchronized (generalMutex) {
								SwingUtilities.updateComponentTreeUI(GraphLayoutPanel.this.getContentPane());
							}
						}
					});
				}
			}
		}
	}
	
	public abstract void onOk();
	public abstract void onExecute();
//=============================================================================
//-----------------PRIVATE METHODS---------------------------------------------
		private void init() {
			// set options for frame
			setTitle("Change layout");
			setSize(400, 200);
			setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
			
			// add panels
			setLayout(new GridBagLayout());
			GridBagConstraints gbc = new GridBagConstraints(0, 0, 2, 1, 1,0,  GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5),  0,0);
			add(layoutList, gbc);
			gbc = new GridBagConstraints(0, 1, 2, 1, 1,0,  GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0),  0,0);
			add(settingsPanel, gbc);
			
			JPanel buttonsPanel = new JPanel();
			buttonsPanel.setLayout(new GridBagLayout());
			gbc = new GridBagConstraints(0, 0, 1, 1, 1,0,  GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5),  0,0);
			buttonsPanel.add(okButton, gbc);
			gbc = new GridBagConstraints(1, 0, 1, 1, 1,0,  GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5),  0,0);
			buttonsPanel.add(executeButton, gbc);			
			gbc = new GridBagConstraints(2, 0, 1, 1, 1,0,  GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5),  0,0);
			buttonsPanel.add(cancelButton, gbc);
			
			gbc = new GridBagConstraints(0, 2, 2, 1, 1,1,  GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),  0,0);		
			add(buttonsPanel, gbc);
			
			settingsPanel.setLayout(new GridBagLayout());

			// add listeners
			okButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {			
					synchronized (generalMutex) {
						onOk();
						setVisible(false);						
					}
				}
			});
			
			executeButton.addActionListener(new ActionListener() {			
				public void actionPerformed(ActionEvent e) {
					synchronized (generalMutex) {
						onOk();
						onExecute();
						//setVisible(false);										
					}
				}
			});
			
			cancelButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					synchronized (generalMutex) {
						setVisible(false);
					}
				}
			});
			
			layoutList.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					synchronized (generalMutex) {
						updateSettingPanel(layoutList.getSelectedIndex());
					}
				}
			});
			
			init = true;
		}

}
